package com.spzx.product.listener;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.rabbitmq.client.Channel;
import com.spzx.common.core.utils.StringUtils;
import com.spzx.product.api.domain.dto.OrderStockDTO;
import com.spzx.product.service.SkuStockService;
import jakarta.annotation.Resource;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.List;
import java.util.Map;

@Component
public class SpzxProductMqListener {
    @Resource
    RedisTemplate redisTemplate;
    @Resource
    SkuStockService skuStockService;
    @RabbitListener(bindings = {
            @QueueBinding(
                    exchange = @Exchange(value = "spzx.payment.exchange",type = ExchangeTypes.TOPIC),
                    value = @Queue(value = "spzx.product.payment.notity.queue"),
                    key = {"spzx.payment.nofity"}
            )
    })
    public void paymentNotify(Map<String,String> messageMap , Message msg , Channel channel){
        try {
            String type = messageMap.get("type");
            String orderNo = messageMap.get("orderNo");
            //获取锁定的库存缓存
            Object o = redisTemplate.opsForValue().get("spzx:order:stock:" + orderNo);
            if(o==null){
                return;
            }
            List<OrderStockDTO> orderStockDTOS = (List<OrderStockDTO>) o;
            if(type.equals("1")){
                //支付成功: 加销量 扣库存
                skuStockService.updateStockAndSales(orderStockDTOS);
            }else{
                //支付失败 释放库存
                //获取redis中缓存的库存信息进行释放
                skuStockService.releaseLockStock(orderStockDTOS);
            }
            //释放库存时 如果有异常，因为使用了事务管理，所以都会失败
            //  以后通过定时任务扫描锁定的库存信息: 通过hash结构来存储锁定的库存信息(包含库存信息  锁定库存的时间...)
            //删除释放成功的库存的缓存
            redisTemplate.delete("spzx:order:stock:" + orderNo);


            // 如果涉及了优惠券和积分
            // 订单支付成功： 无需操作
            // 订单支付失败： 释放锁定的优惠券，扣除之前提交订单时的积分
            channel.basicAck(msg.getMessageProperties().getDeliveryTag() , false);
        } catch (Exception e) {
            try {
                if(msg.getMessageProperties().isRedelivered()){
                    channel.basicReject(msg.getMessageProperties().getDeliveryTag() ,false);
                }else{
                    channel.basicNack(msg.getMessageProperties().getDeliveryTag() ,false,true);
                }
            } catch (IOException ex) {
                throw new RuntimeException(ex);
            }
        }

    }
    @RabbitListener(bindings = {
            @QueueBinding(
                    exchange = @Exchange(value = "spzx.order.exchange",type = ExchangeTypes.TOPIC),
                    value = @Queue(value = "spzx.product.order.close.queue"),
                    key = {"spzx.order.close.success"}
            )
    })
    public void releaseStock(Message message , String msg , Channel channel){

        try {
            if(StringUtils.isEmpty(msg)){
                return;
            }
            //获取redis中缓存的库存信息进行释放
            Object o = redisTemplate.opsForValue().get("spzx:order:stock:" + msg);
            if(o==null){
                return;
            }
            List<OrderStockDTO> orderStockDTOS = (List<OrderStockDTO>) o;
            skuStockService.releaseLockStock(orderStockDTOS);
            //释放库存时 如果有异常，因为使用了事务管理，所以都会失败
            //  以后通过定时任务扫描锁定的库存信息: 通过hash结构来存储锁定的库存信息(包含库存信息  锁定库存的时间...)
            //删除释放成功的库存的缓存
            redisTemplate.delete("spzx:order:stock:" + msg);

            channel.basicAck(message.getMessageProperties().getDeliveryTag() , false);
        } catch (Exception e) {
            try {
                if(message.getMessageProperties().isRedelivered()){
                    channel.basicReject(message.getMessageProperties().getDeliveryTag(),false);
                }else{
                    channel.basicNack(message.getMessageProperties().getDeliveryTag(), false,true);
                }
            } catch (IOException ex) {
                throw new RuntimeException(ex);
            }
        }

    }
}
